﻿#pragma once

namespace LK
{
	/**
	@brief 异常类型，在检测到错误时抛出*/
	struct PException : PObject
	{
	public:
		//通用基类方法
		PMETHODS(PException, Exception);
		/**
		@brief 获取错误描述字符串*/
		PString GetDescription() const;
		/**
		@brief 获取内部错误的引用*/
		PException GetInnerException() const;
		/**
		@brief 使用一个字符串来初始化*/
		PException(PString description)throw();
		/**
		@brief 使用一个字符串、内部错误来初始化*/
		PException(PString description, PException innerException)throw();
	};
	/**
	@brief 异常类型实体*/
	struct Exception :virtual Object, virtual ICloneables
	{
	protected:
		/**
		@brief 错误描述*/
		PString description;
		/**
		@brief 内部错误*/
		PException Inner;
	public:
		/**
		@brief 通用基类方法*/
		BMETHODS(PException, Exception)
		/**
		@brief 默认构造函数*/
		Exception()throw();
		/**
		@brief 复制构造函数*/
		Exception(const Exception& e)throw();
		/**
		@brief 使用一个字符串来初始化*/
		Exception(PString description)throw();
		/**
		@brief 使用一个字符串、内部错误来初始化*/
		Exception(PString  description, PException innerException)throw();
		/**
		@brief 返回一个浅表副本*/
		Exception* Clone()const { return new Exception(*this); }
		/**
		@brief 析构函数*/
		~Exception();
		/**
		@brief 到字符串的转换*/
		PString ToString()const;
		/**
		@brief 获取错误描述的*/
		PString GetDescription();
		/**
		@brief 获取内部错误*/
		PException GetInnerException();
		/**
		@brief 判断是否相等*/
		bool Equals(const Object&)const;
	};

	/**
	@brief 除了PMETHODS外，还声明了PException常用的构造方法：
	Xobj();默认构造一个新的异常对象，传入默认的错误描述
	Xobj(const PString& description);使用指定的错误描述来构造异常对象
	Xobj(const PString& description, const PException& innerException);使用指定的错误描述和内部异常来构造异常对象*/
#define PEXCEPTION(NAME,DEFDISCRIPTION)\
	P##NAME( )throw(); \
	/*使用一个字符串来初始化*/\
	P##NAME(PString description)throw(); \
	/*使用一个字符串、内部错误来初始化*/\
	P##NAME(PString description, PException innerException)throw(); \
	/*基类方法*/\
	PMETHODS_NODEFCTOR(P##NAME, NAME);

	/**
	@brief 除了BMETHODS外，还定义了Exception常用的构造方法：
	Vobj();默认构造一个新的异常对象，传入默认的错误描述
	Vobj(const PString& description);使用指定的错误描述来构造异常对象
	Vobj(const PString& description, const PException& innerException);使用指定的错误描述和内部异常来构造异常对象*/
#define BEXCEPTION(NAME,BASE,DEFDISCRIPTION)\
	/*默认构造*/\
	NAME()throw() :BASE(DEFDISCRIPTION){}\
	/*使用一个字符串来初始化*/\
	NAME(PString description)throw() :BASE(description){}\
	/*使用一个字符串、内部错误来初始化*/\
	NAME(PString description, PException innerException)throw() :BASE(description, innerException){}\
	/*基类方法*/\
	BMETHODS(P##NAME, NAME)

	//定义通用异常类的宏（从Base派生后没有其他附加信息）
#define EXCEPTION_DEFINE(NAME,DEFDISCRIPTION,BASE)\
	struct NAME;\
	struct P##NAME : P##BASE\
	{public:PEXCEPTION(NAME, DEFDISCRIPTION)\
	static inline P##NAME& GetDefaultRef();\
	};\
	struct NAME : BASE\
	{public:BEXCEPTION(NAME, BASE, DEFDISCRIPTION)\
	NAME* Clone()const { return new NAME(*this); }};\
	P##NAME& P##NAME::GetDefaultRef()\
	{static PObject obj;if(!obj.IsNull())return(P##NAME&)obj;\
	SpinMutex::GetDefaultRef().Lock();if(obj.IsNull()){NAME*p = new NAME();p->RefCount.SetEnableInterlocked(true);obj=p;}\
	SpinMutex::GetDefaultRef().UnLock();return(P##NAME&)obj; }\
	inline P##NAME::P##NAME()throw() :P##BASE(P##NAME::GetDefaultRef()){} \
	inline P##NAME::P##NAME(PString description)throw() :P##BASE(new NAME(description)){} \
	inline P##NAME::P##NAME(PString description,  PException innerException)throw() :P##BASE(new NAME(description,  innerException)){}

	EXCEPTION_DEFINE(PointerIsNullException, L"尝试对空指针解引用", Exception)
	EXCEPTION_DEFINE(PointerFailureException, L"指针已经失效", Exception)
	EXCEPTION_DEFINE(OutOfMemoryException, L"发生内存溢出错误", Exception)
	EXCEPTION_DEFINE(IndexOutOfRangeException, L"检测到下标越界", Exception)
	EXCEPTION_DEFINE(InvalidArgumentException, L"参数无效", Exception)
	EXCEPTION_DEFINE(TypesCheckingErrorException, L"类型检查错误", Exception)
	EXCEPTION_DEFINE(TypesConvertErrorException, L"类型转换错误", Exception)
	EXCEPTION_DEFINE(NotSupportException, L"该项操作不被支持", Exception)


}
